/*
 * Copyright 2010 Chad Retz
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.jdocng.cmd;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;

import org.jdocng.parse.ParserFactory;
import org.jdocng.shared.JavadocNgException;
import org.jdocng.shared.context.Context;
import org.jdocng.util.ConfigurationUtils;

import com.sun.javadoc.RootDoc;

/**
 * Compatibility checker that checks an alternate VM's {@link RootDoc}.
 * This will execute the third-party javadoc as normal during this process. 
 * In addition to all other standard javadoc options passed in, four 
 * more options must be passed:
 * <ul>
 * <li>-toolClass &lt;TOOL_CLASS_NAME&gt; - This is the FQCN of
 *  a class containing a method returning an instance of {@link RootDoc}.</li>
 * <li>-toolMethod &lt;TOOL_CLASS_METHOD_NAME&gt; - This is the name
 *  of a method in the class that returns an instance of {@link RootDoc}.</li>
 * <li>-toolMainClass &lt;TOOL_MAIN_CLASS_NAME&gt; - This is the FQCN
 *  of the class containing the static a static method that starts the
 *  javadoc process.</li>
 * <li>-toolMainMethod &lt;TOOL_MAIN_METHOD_NAME&gt; - This is the name
 *  of the static method that starts the javadoc process accepting
 *  a string array of arguments</li>
 * </ul>
 *
 * @author Chad Retz
 */
public class CheckCompat {

    private static RootDoc rootDoc;
    
    /**
     * Called by the third party library to set the root doc
     * 
     * @param rootDoc
     */
    public static void setRootDoc(RootDoc rootDoc) {
        CheckCompat.rootDoc = rootDoc;
    }
    
    /**
     * Execute the compatibility checker
     * 
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        //get the args and remove em...
        List<String> properArgs = new ArrayList<String>(Arrays.asList(args));
        int index = properArgs.indexOf("-toolClass");
        if (index == -1) {
            throw new IllegalArgumentException("-toolClass not defined");
        }
        String toolClassName = properArgs.remove(index + 1);
        properArgs.remove(index);
        index = properArgs.indexOf("-toolMethod");
        if (index == -1) {
            throw new IllegalArgumentException("-toolMethod not defined");
        }
        String toolMethodName = properArgs.remove(index + 1);
        properArgs.remove(index);
        index = properArgs.indexOf("-toolMainClass");
        if (index == -1) {
            throw new IllegalArgumentException("-toolMainClass not defined");
        }
        String toolMainClassName = properArgs.remove(index + 1);
        properArgs.remove(index);
        index = properArgs.indexOf("-toolMainMethod");
        if (index == -1) {
            throw new IllegalArgumentException("-toolMainMethod not defined");
        }
        String toolMainMethodName = properArgs.remove(index + 1);
        properArgs.remove(index);
        //remove written class if it was already there...
        File writtenClassFile = new File("tmp/" + toolClassName.replace(".", 
                File.separator) + ".class");
        if (writtenClassFile.exists()) {
            writtenClassFile.delete();
        }
        //we surround the class
        CtClass toolClass = ClassPool.getDefault().get(toolClassName);
        CtMethod oldGetMethod = toolClass.getDeclaredMethod(toolMethodName);
        //rename it...
        oldGetMethod.setName(toolMethodName + "$impl");
        //create new by copying
        CtMethod newGetMethod = CtNewMethod.copy(oldGetMethod,
                toolMethodName, toolClass, null);
        //add some contents to toss the error
        StringBuilder contents = new StringBuilder("{\n    ");
        contents.append(newGetMethod.getReturnType().getName());
        contents.append(" result = ");
        contents.append(toolMethodName);
        contents.append("$impl($$);\n    ");
        contents.append(CheckCompat.class.getName());
        contents.append(".setRootDoc(result);\n    return result;}");
        newGetMethod.setBody(contents.toString());
        //set in class and write
        toolClass.addMethod(newGetMethod);
        toolClass.writeFile("./tmp");
        writtenClassFile.deleteOnExit();
        //now call the Javadoc stuff
        Class.forName(toolMainClassName).getDeclaredMethod(
                toolMainMethodName, String[].class).invoke(null, 
                        (Object) properArgs.toArray(new String[0]));
        //we got a root doc?
        if (rootDoc == null) {
            throw new JavadocNgException("Unable to obtain RootDoc");
        }
        //so we do? ok, parse NG style
        @SuppressWarnings("unused")
        Context context = ParserFactory.parse(ConfigurationUtils.parse(
                properArgs.toArray(new String[0])));
        //and check...
        //TODO
        throw new UnsupportedOperationException();
    }
}
